package utils

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v4"
)

type CustomClaims struct {
	// 可根据需要自行添加字段
	Username             string `json:"username"`
	jwt.RegisteredClaims        // 内嵌标准的声明
}

// 用于签名的字符串
var mySigningKey = []byte("jediborn")

// CreateToken 使用默认声明创建jwt
func CreateToken(account string) (string, error) {
	// 创建 Claims
	claims := CustomClaims{
		account,
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)), // 过期时间
			Issuer:    "jediborn",                                         // 签发人
		},
	}
	// 生成token对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 生成签名字符串
	return token.SignedString(mySigningKey)
}

// ParseToken 解析jwt
func ParseToken(tokenString string) bool {
	// 解析token
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return mySigningKey, nil
	})
	if err != nil { // 解析token失败
		return false
	}
	return token.Valid
}

func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		re, err := regexp.Compile("/swagger/")
		if err != nil {
			return
		}

		path := c.Request.URL.Path
		fmt.Println(c.Request.URL.Path)
		if (path == "/api/login") || (path == "/api/register") || re.MatchString(path) {
			c.Next()
			return
		}
		// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
		// 这里假设Token放在Header的Authorization中，并使用Bearer开头
		// 这里的具体实现方式要依据你的实际业务情况决定
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code":    401,
				"message": "请携带token",
			})
			c.Abort()
			return
		}
		//按空格分割
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.JSON(http.StatusBadRequest, gin.H{
				"code":    2004,
				"message": "请求头中auth格式有误",
			})
			c.Abort()
			return
		}

		//parts[1]是获取到的token，我们就解析它
		bol := ParseToken(parts[1])
		if !bol {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code":    401,
				"message": "无效token",
			})
			c.Abort()
			return
		}
		c.Next()
	}
}
